package rpc_netty.LoadBalancerImpl;

import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.pojo.Instance;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import rpc_netty.Client.conf.ConfigureMagment_client;
import rpc_netty.interfaces.LoadBalancer;
import rpc_netty.server.conf.ConfigureMagment;

import java.util.List;
import java.util.concurrent.ThreadLocalRandom;


//基于权重的随机负载均衡
public class RandomLoadBalancer implements LoadBalancer {
    private static Logger logger= LoggerFactory.getLogger(RandomLoadBalancer.class);
    private final ConfigureMagment_client configureMagment_client=ConfigureMagment_client.getConfigureMagment_client();
    //通过nacos提供的配置中心获取服务的上线时间
    private static ConfigService configService;

    public RandomLoadBalancer(){
        String url = configureMagment_client.getProperty("ServiceRegistryUrl");
        try {
            configService= NacosFactory.createConfigService(url);
        } catch (NacosException e) {
            e.printStackTrace();
        }
    }

    @Override
    public Instance select(List<Instance> instances) {
        //获取提供服务的实例数量
        int size = instances.size();
        if (size==0){
            logger.error("No available instance!");
            return null;
        }
        if (size==1)
            return instances.get(0);
        //判断权重是否相同
        boolean sameWeight=true;
        int[] weights=new int[size];
        int totalWeight=0;
        for (int i=0;i<size;i++){
            int weight=getWeight(instances.get(i));
            totalWeight+=weight;
            weights[i]=totalWeight;
            if (sameWeight&&totalWeight!=weight*(i+1))
                sameWeight=false;
        }
        //当总权重>0并且权重并不相等时，根据权重随机选择实例
        if (totalWeight>0&&!sameWeight){
            int offset= ThreadLocalRandom.current().nextInt(totalWeight);
            for (int i=0;i<size;i++){
                if (offset<weights[i])
                    return instances.get(i);
            }
        }
        return instances.get(ThreadLocalRandom.current().nextInt(size));
    }

    //获取权重，warmup机制
    //在warmup时间内的服务，warmup的时间越短，相应的weight会越低，从而让warmup时间更久的（编译优化更成熟的）服务获得更多负载
    public int getWeight(Instance instance)  {
        int weight = (int)instance.getWeight();
        weight=weight<=100?100:weight;
        String timestamp = null;
        try {
            String clusterName = instance.getClusterName();
            int len=clusterName.length()+8;
            String pure_name=instance.getServiceName().substring(len);
            timestamp = configService.getConfig(pure_name,instance.getIp()+":"+instance.getPort(),3000);
        } catch (NacosException e) {
            e.printStackTrace();
        }
        if (timestamp==null)
            return 0;
        long timestampl = Long.parseLong(timestamp);
        if (timestampl>0L){
            long uptime=System.currentTimeMillis()-timestampl;
            if (uptime<0)
                return 1;
            String warmup = configureMagment_client.getProperty("warmup");
            int warmupi= warmup == null ? 600000 : Integer.parseInt(warmup);
            if (uptime>0&&uptime<warmupi)
                weight=calculateWarmupWeight((int)uptime,warmupi,weight);
        }
        return Math.max(weight,0);
    }
    static int calculateWarmupWeight(int uptime, int warmup, int weight) {
        int ww = (int) ( uptime / ((float) warmup / weight));
        return ww < 1 ? 1 : (Math.min(ww, weight));
    }

}
